package com.huiquan.analysis.job;

import com.alibaba.fastjson.JSON;
import com.huiquan.analysis.constants.AnalysisSentenceConstant;
import com.huiquan.analysis.dao.AnalysisSentenceDao;
import com.huiquan.analysis.dao.AnalysisVocabularyDao;
import com.huiquan.analysis.domain.AnalysisSentenceJson;
import com.huiquan.analysis.domain.AnalysisVocabulary;
import com.huiquan.analysis.domain.AnalysisVocabularyJson;
import com.huiquan.analysis.utils.ListUtil;
import com.huiquan.foundation.util.BusinessUtil;
import com.huiquan.framework.utils.DateUtils;
import com.huiquan.framework.utils.FileUtils;
import com.huiquan.framework.utils.HttpRequest;
import net.sf.json.JSONArray;
import net.sf.json.JSONObject;
import org.apache.commons.lang.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;

import java.io.*;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

@Component
public class AnalysisInit {

    private static final Logger LOG = LoggerFactory.getLogger(AnalysisInit.class);

    @Value("${init.zs.sentence.path}")
    private String zsPath;
    @Value("${init.ct.sentence.path}")
    private String ctPath;
    @Value("${init.xbs.sentence.path}")
    private String xbsPath;

    @Value("${init.sentence.bme.result.zs.path}")
    private String zsResultPath;
    @Value("${init.sentence.bme.result.ct.path}")
    private String ctResultPath;
    @Value("${init.sentence.bme.result.sid.zs.path}")
    private String zsResultWithSidPath;
    @Value("${init.sentence.bme.result.sid.ct.path}")
    private String ctResultWithSidPath;
    @Value("${init.sentence.bme.result.xbs.path}")
    private String xbsResultPath;
    @Value("${init.sentence.bme.result.xbs.nolabel.path}")
    private String xbsNoLabelResultPath;
    @Value("${init.sentence.bme.result.sid.xbs.path}")
    private String xbsResultWithSidPath;

    @Value("${init.sentence.load.zs.script}")
    private String loadZsScript;
    @Value("${init.sentence.load.ct.script}")
    private String loadCtScript;
    @Value("${init.sentence.load.xbs.script}")
    private String loadXbsScript;
    @Value("${init.sentence.execute.label.zs.script}")
    private String executeLabelZsScript;
    @Value("${init.sentence.execute.label.ct.script}")
    private String executeLabelCtScript;
    @Value("${init.sentence.execute.label.xbs.script}")
    private String executeLabelXbsScript;

    @Autowired
    private AnalysisVocabularyDao analysisVocabularyDao;
    @Autowired
    private AnalysisSentenceDao analysisSentenceDao;

    /**
     * 初始化主诉数据
     *
     * @throws Exception
     */
    public void initZs() throws Exception {
        LOG.info("Analysis init job init zs begin!");

        doInit(AnalysisSentenceConstant.TYPE_ZS, null);

        LOG.info("Analysis init job init zs end!");
    }

    /**
     * 初始化医学影像数据
     *
     * @throws Exception
     */
    public void initCt() throws Exception {
        LOG.info("Analysis init job init ct begin!");

        doInit(AnalysisSentenceConstant.TYPE_CT, null);

        LOG.info("Analysis init job init ct end!");
    }

    /**
     * 初始化现病史数据
     *
     * @throws Exception
     */
    public void initXbs() throws Exception {
        LOG.info("Analysis init job init xbs begin!");

        // 根据第二个类别分别进行预标注
        for (String sencondType : AnalysisSentenceConstant.XBS_SOURCE_TYPE_PRE_LABEL_TYPE.keySet()) {
            doInit(AnalysisSentenceConstant.TYPE_XBS, sencondType);
        }

        LOG.info("Analysis init job init xbs end!");
    }

    /**
     * 初始化现病史数据
     *
     * @throws Exception
     */
    public void initXbs(String sencondType) throws Exception {
        LOG.info("Analysis init job init xbs begin!");

        // 根据第二个类别分别进行预标注
        doInit(AnalysisSentenceConstant.TYPE_XBS, sencondType);

        LOG.info("Analysis init job init xbs end!");
    }

    /**
     * 预标注
     *
     * @param type       1:主诉2:现病史3
     * @param secondType
     * @throws Exception
     */
    private void doInit(int type, String secondType) throws Exception {
        List<Map<String, Object>> list = null;
        String ulFilePath = "";
        if (type == AnalysisSentenceConstant.TYPE_ZS) {
            ulFilePath = BusinessUtil.getCompletePath4Properties(zsPath);
            list = analysisSentenceDao.retrieveSidAndSentence(type, AnalysisSentenceConstant.LABEL_STATUS_UNLABELED);
        } else if (isXbs(type)) {
            list = analysisSentenceDao.retrieveXbsSidAndSentence(AnalysisSentenceConstant.XBS_BME_FLAG_Y,
                    AnalysisSentenceConstant.LABEL_STATUS_SUBPACKAGED, secondType);
            ulFilePath = BusinessUtil.getCompletePath4Properties(xbsPath);
        } else if (type == AnalysisSentenceConstant.TYPE_CT) {
            ulFilePath = BusinessUtil.getCompletePath4Properties(ctPath);
            list = analysisSentenceDao.retrieveSidAndSentence(type, AnalysisSentenceConstant.LABEL_STATUS_UNLABELED);
        }
        if (ListUtil.isEmpty(list)) {
            LOG.info("Get sid and sentence fail,list is empty,type:" + type);
            return;
        }

        LOG.info("Get sid and sentence success, size=" + list.size());

        StringBuilder ulSb = new StringBuilder();
        for (Map<String, Object> map : list) {
            ulSb.append(map.get("sentence"));
            ulSb.append("\n");
        }
        FileUtils.generateFile(ulFilePath, ulSb.toString());
        LOG.info("创建预处理输入文件成功!");

        // 运行shell脚本进行处理
        String script = null;
        String param = "";
        if (type == AnalysisSentenceConstant.TYPE_ZS) {
            script = executeLabelZsScript;
        } else if (isXbs(type)) {
            script = executeLabelXbsScript;
            param = AnalysisSentenceConstant.XBS_SOURCE_TYPE_PRE_LABEL_TYPE.get(secondType);
        } else if (type == AnalysisSentenceConstant.TYPE_CT) {
            script = executeLabelCtScript;
        }

        String result = "error";
        result = BusinessUtil.excuteShell(new String[]{script, param});
        LOG.info("执行预处理脚本成功! result=" + result);
        // 对预标注结果进行处理
        dealLabelResult(type, list, param);
        LOG.info("预标注处理结束，处理类型:" + type);
    }

    @Value("${init.zs.sentence.bme.pre.path}")
    private String zsBmePrePath;
    @Value("${init.zs.sentence.bme.script}")
    private String zsBmeScript;
    @Value("${init.ct.sentence.bme.pre.path}")
    private String ctBmePrePath;
    @Value("${init.ct.sentence.bme.script}")
    private String ctBmeScript;
    @Value("${init.xbs.sentence.bme.pre.path}")
    private String xbsBmePrePath;
    @Value("${init.xbs.sentence.bme.script}")
    private String xbsBmeScript;

    /**
     * 进行bme标注并处理数据
     *
     * @param list
     * @throws Exception
     */
    public void doBmeInit(List<AnalysisVocabulary> list, int type, String param) throws Exception {
        String ulFilePath = "";
        if (type == AnalysisSentenceConstant.TYPE_ZS) {
            ulFilePath = BusinessUtil.getCompletePath4Properties(zsBmePrePath);
        } else if (isXbs(type)) {
            ulFilePath = BusinessUtil.getCompletePath4Properties(xbsBmePrePath);
        } else if (type == AnalysisSentenceConstant.TYPE_CT) {
            ulFilePath = BusinessUtil.getCompletePath4Properties(ctBmePrePath);
        }
        StringBuilder ulSb = new StringBuilder();
        long sid = -1;
        List<Map<String, Object>> mapList = new ArrayList<>();
        Map<String, Object> map = null;
        for (AnalysisVocabulary temp : list) {
            if (sid < 0) {
                sid = temp.getSid();
                map = new HashMap<>();
                map.put("id", temp.getSid());
                mapList.add(map);
            } else if (sid != temp.getSid()) {
                ulSb.append("\n");
                sid = temp.getSid();
                map = new HashMap<>();
                map.put("id", temp.getSid());
                mapList.add(map);
            }
            ulSb.append(temp.getVocabulary());
            ulSb.append("\t");
            ulSb.append(temp.getCharacteristic());
            ulSb.append("\t");
            ulSb.append(temp.getProperty());
            ulSb.append("\n");
        }
        FileUtils.generateFile(ulFilePath, ulSb.toString());
        LOG.info("创建BME处理输入文件成功!");

        // 运行shell脚本进行处理
        String script = null;
        if (type == AnalysisSentenceConstant.TYPE_ZS) {
            script = zsBmeScript;
        } else if (isXbs(type)) {
            script = xbsBmeScript;
        } else if (type == AnalysisSentenceConstant.TYPE_CT) {
            script = ctBmeScript;
        }
        String result = "error";
        result = BusinessUtil.excuteShell(new String[]{script, param});
        LOG.info("执行BME处理脚本成功! result=" + result);
        // 对预标注结果进行处理
        dealLabelResult(type, mapList, param);
        LOG.info("BME处理结束，处理类型:" + type);
    }

    /**
     * 对预标注结果进行处理
     *
     * @param type
     * @param list
     * @param preLabelType
     * @throws IOException
     */
    private void dealLabelResult(int type, List<Map<String, Object>> list, String preLabelType) throws IOException {
        // 对预处理的结果文件进行处理，加入sid
        String resultFilePath = null;
        String resultWithSidPath = null;
        boolean bmeFlag = true;
        if (type == AnalysisSentenceConstant.TYPE_ZS) {
            resultFilePath = BusinessUtil.getCompletePath4Properties(zsResultPath);
            resultWithSidPath = BusinessUtil.getCompletePath4Properties(zsResultWithSidPath);
        } else if (isXbs(type)) {
            resultFilePath = BusinessUtil.getCompletePath4Properties(xbsResultPath + preLabelType);
            if (!new File(resultFilePath).exists()) {
                bmeFlag = false;
                resultFilePath = BusinessUtil.getCompletePath4Properties(xbsNoLabelResultPath + preLabelType);
            }
            resultWithSidPath = BusinessUtil.getCompletePath4Properties(xbsResultWithSidPath);
        } else if (type == AnalysisSentenceConstant.TYPE_CT) {
            resultFilePath = BusinessUtil.getCompletePath4Properties(ctResultPath);
            resultWithSidPath = BusinessUtil.getCompletePath4Properties(ctResultWithSidPath);
        }
        int count = 0;
        File resultFile = new File(resultFilePath);
        OutputStreamWriter writer = new OutputStreamWriter(new FileOutputStream(resultWithSidPath), "UTF-8");
        if (resultFile.isFile() && resultFile.exists()) { // 判断文件是否存在
            LOG.info("对处理结果添加sid");
            InputStreamReader read = new InputStreamReader(new FileInputStream(resultFile), "UTF-8");// 考虑到编码格式
            BufferedReader bufferedReader = new BufferedReader(read);
            String lineTxt = null;
            ArrayList<String> lineList = new ArrayList<>();
            if (!bmeFlag) {
                while ((lineTxt = bufferedReader.readLine()) != null) {
                    if ("".equals(lineTxt.trim())) {
                        count++;
                    } else {
                        if (lineTxt.startsWith("#")) {
                            continue;
                        }
                        // 将id写入为sid
                        writer.write(String.valueOf(list.get(count).get("id")));
                        writer.write("\t");
                        writer.write(lineTxt);
                        writer.write("\n");
                    }
                }
                read.close();
                writer.flush();
                writer.close();
                LOG.info("添加sid完成1,count=" + count);
            } else {
                while ((lineTxt = bufferedReader.readLine()) != null) {
                    if ("".equals(lineTxt)) {
                        count++;
                    } else {
                        if (lineTxt.startsWith("#") && lineTxt.split("\t").length < 3) {
                            String reliability = lineTxt.substring(2);
                            for (String line : lineList) {
                                // 将id写入为sid
                                writer.write(String.valueOf(list.get(count).get("id")));
                                writer.write("\t");
                                writer.write(line);
                                // 将可信度写入
                                writer.write("\t");
                                writer.write(reliability);
                                writer.write("\n");
                            }
                            lineList.clear();
                        } else {
                            lineList.add(lineTxt);
                        }
                    }
                }
                read.close();
                writer.flush();
                writer.close();
                LOG.info("添加sid完成2,count=" + count);
            }
        }
        LOG.info("读取带sid的处理结果插入到临时表中");
        String script = null;
        // 读取文件写入到MySql的临时表中
        if (type == AnalysisSentenceConstant.TYPE_ZS) {
            script = loadZsScript;
        } else if (isXbs(type)) {
            script = loadXbsScript;
        } else if (type == AnalysisSentenceConstant.TYPE_CT) {
            script = loadCtScript;
        }
        String cmds[] = {script};
        String result = "error";
        result = BusinessUtil.excuteShell(cmds);
        LOG.info("读取带sid的处理结果插入到临时表中成功! result=" + result);
        // 将临时表里的数据维护到bas_analysis_vocabulary表中
        if (type == AnalysisSentenceConstant.TYPE_ZS) {
            LOG.info("初始化主诉BME数据开始");
            analysisVocabularyDao.initZsBme();
            LOG.info("初始化主诉BME数据结束");
        } else if (isXbs(type)) {
            LOG.info("初始化现病史BME数据开始");
            analysisVocabularyDao.initXbsBme();
            LOG.info("初始化现病史BME数据结束");
        } else if (type == AnalysisSentenceConstant.TYPE_CT) {
            LOG.info("初始化医学影像BME数据开始");
            analysisVocabularyDao.initCtBme();
            LOG.info("初始化医学影像BME数据结束");
        }
    }

    @Value("${init.xbs.data.script}")
    private String xbsDataScript;

    /**
     * 初始化现病史数据
     *
     * @throws IOException
     */
//	public void initXbsData() throws IOException {
//		// 从hive中获取数据同步到mysql
//		LOG.info("同步现病史数据开始，从181获取数据");
//		BusinessUtil.excuteShell(new String[] { xbsDataScript });
//		// 清除未标注的现病史数据
//		analysisSentenceDao.deleteUnlabelXbsBmeData();
//		// 取得外包人员数量
//		int outsourcingPersonnelCount = analysisSentenceDao.selectOutsourcingPersonnelCount();
//		LOG.info("外包人员数量" + outsourcingPersonnelCount);
//		// 定义外包人员的工作量
//		int lowLength = analysisSentenceDao.getSentenceLength(1, 1);
//		LOG.info("句子最短字数：" + lowLength);
//		
//		int highLength = analysisSentenceDao.getSentenceLength(1, 2);
//		// analysisSentenceDao.initXbsBmeData(outsourcingPersonnelCount *
//		// outsourcingPersonnelWorkload);
//		int outsourcingPersonnelWorkload = 5120;
//		LOG.info("句子最长字数：" + highLength);
//		
//		analysisSentenceDao.initXbsBmeDataBySentenceLength(null, lowLength, highLength,
//				outsourcingPersonnelCount * outsourcingPersonnelWorkload);
//		LOG.info("同步现病史数据结束");
//	}

    /**
     * 初始化现病史数据
     *
     * @throws IOException
     */
    public void initXbsDataWithSecondType(String secondType) throws IOException {
        // 从hive中获取数据同步到mysql
        LOG.info("同步现病史数据开始，从181获取数据");
        BusinessUtil.excuteShell(new String[]{xbsDataScript});
        // 清除未标注的现病史数据
        analysisSentenceDao.deleteUnlabelXbsBmeData();
        // 取得外包人员数量
        int outsourcingPersonnelCount = analysisSentenceDao.selectOutsourcingPersonnelCount();
        LOG.info("外包人员数量" + outsourcingPersonnelCount);
        // 加一个人谭姐
        outsourcingPersonnelCount++;
        // 定义外包人员的工作量
        int outsourcingPersonnelWorkload = 5120;

        int lowLength = analysisSentenceDao.getSentenceLength(1, 1);
        LOG.info("句子最短字数：" + lowLength);
        int highLength = analysisSentenceDao.getSentenceLength(1, 2);
        LOG.info("句子最长字数：" + highLength);
        // 暂时取消了数量限制
        analysisSentenceDao.initXbsBmeDataBySentenceLength(secondType, lowLength, highLength,
                outsourcingPersonnelCount * outsourcingPersonnelWorkload);
        LOG.info("同步现病史数据结束");
    }

    /**
     * 根据类型判断是否是现病史
     *
     * @param type
     * @return
     */
    private boolean isXbs(int type) {
        return (type == AnalysisSentenceConstant.TYPE_XBS || type > 20);
    }
}
